package sql

import (
	"database/sql"
	"fmt"
	"strings"

	_ "github.com/go-sql-driver/mysql"
)

type Mysql struct {
	db *sql.DB
}

func (t *Mysql) Conn(info *SqlInfo) (err error) {
	db, err := sql.Open("mysql", fmt.Sprintf(
		"%s:%s@tcp(%s)/%s?charset=utf8", // "用户名:密码@tcp(IP:端口)/数据库?charset=utf8"。
		info.UserName,
		info.Password,
		info.Address,
		info.DBname,
	))
	if err != nil {
		return fmt.Errorf("%s conn error %+v", info.SqlType, err)
	}
	fmt.Printf("%s conn [ok]\n", info.SqlType)
	// db.SetConnMaxLifetime(time.Minute * 3)
	// db.SetMaxOpenConns(10)
	// db.SetMaxIdleConns(10)
	err = db.Ping()
	if err != nil {
		return fmt.Errorf("%s ping error %+v", info.SqlType, err)
	}
	t.db = db
	return
}

func (t *Mysql) Select(tableName string, columns []string) (result [][]string, err error) {
	row, err := t.db.Query(fmt.Sprintf("select %s from %s", strings.Join(columns, ","), tableName))
	if err != nil {
		return nil, fmt.Errorf("Query tableName=%s err=%v", tableName, err)
	}

	defer row.Close()
	l, err := row.Columns()
	if err != nil {
		return nil, fmt.Errorf("Columns err=%v", err)
	}
	list := make([]interface{}, len(l))
	for k := range list {
		temp := ""
		list[k] = &temp
	}

	for row.Next() {
		err = row.Scan(list...)
		if err != nil {
			return nil, fmt.Errorf("Scan err=%v", err)
		}
		arr := make([]string, len(l))
		for k := range list {
			arr[k] = *list[k].(*string)
		}

		result = append(result, arr)
	}
	return
}

func (t *Mysql) Insert(tableName string, columns, args []string) error {
	stmt, err := t.db.Prepare(fmt.Sprintf("INSERT INTO %s(%s) VALUES('%s')", tableName, strings.Join(columns, ","), strings.Join(args, "','")))
	if err != nil {
		return err
	}
	_, err = stmt.Exec()
	return err
}

func (t *Mysql) Update(tableName, id string, um map[string]string) error {
	var uv []string
	for k, v := range um {
		uv = append(uv, fmt.Sprintf("%s='%s'", k, v))
	}
	stmt, err := t.db.Prepare(fmt.Sprintf("UPDATE %s set %s where id=%s", tableName, strings.Join(uv, ","), id))
	if err != nil {
		return err
	}
	_, err = stmt.Exec()
	return err
}

func (t *Mysql) Delete(tableName, id string) error {
	stmt, err := t.db.Prepare(fmt.Sprintf("DELETE from %s where id=%s", tableName, id))
	if err != nil {
		return err
	}
	_, err = stmt.Exec()
	return err
}
